package com.fit.utils.dev.code.generation.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.fit.utils.dev.code.generation.model.TablePrimaryModel;
import com.fit.utils.se.EmptyUtils;
import com.fit.utils.se.IOUtil;
import com.fit.utils.se.StringUtil;
import com.fit.utils.se.VelocityUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.VelocityContext;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 生成代码依赖工具
 * @author hcl
 *
 */
@Slf4j
public class GeneratorUtils {
	
	
	
	
	/**
	 * 根据模板名称获取模板对象
	 * @param templateNmae
	 * @return
	 */
	public static String getTemplate(String templateNmae){
		try {
			String context = IOUtil.toString(MyBatisGeneratorUtils.class.getResourceAsStream("/template/"+templateNmae));
			return context;
		} catch (IOException e) {
			log.error("模板 {} 获取异常！",templateNmae,e);
			throw new RuntimeException("模板获取异常！",e);
		}
		
	}
	
	
	/**
	 * 根据模板生成文件
	 * @param fileDirPath
	 * @param fileName
	 * @param template
	 * @param context
	 * @param idCover 是否覆盖
	 */
	public static void generator(String fileDirPath,String fileName,String template,VelocityContext context,boolean idCover){
		fileDirPath = fileDirPath.replaceAll("\\\\", "/");
		fileDirPath = createDirs(fileDirPath);
		File file = new File(fileDirPath+fileName);
		if(idCover && file.exists()){
			file.delete();
		}
		if(file.exists()){
			log.info("{} 已经存在,跳过！",file.getAbsoluteFile());
			return ;
		}
		try {
			VelocityUtil.generateTemplateStrInstance(context, template,new FileWriter(file));
		} catch (IOException e) {
			log.error("生成 {} 文件失败！",file.getAbsoluteFile(),e);
			throw new RuntimeException("根据模板生成文件失败！",e);
		}
	}
	
	
	/**
	 * 生成根据配置文件生成model
	 * @param configIn
	 */
	public static void generateByConfig(InputStream configIn){
		try {
			List<String> warnings = new ArrayList<String>();
			boolean overwrite = true;
			ConfigurationParser cp = new ConfigurationParser(warnings);
			Configuration config = cp.parseConfiguration(configIn);
			DefaultShellCallback callback = new DefaultShellCallback(overwrite);
			MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
			myBatisGenerator.generate(null);
		} catch (Exception e) {
			log.error("生成model异常！", e);
			throw new RuntimeException("生成model异常！",e);
		}finally{
			IOUtil.close(configIn);
		}
	}
	
	
	/**
	 * 获取公共的VelocityContext
	 * @return
	 */
	public static VelocityContext getCommonContext(TablePrimaryModel tablePrimaryModel,String modelPackage){
		VelocityContext context = new VelocityContext();
		String tablePrefix = tablePrimaryModel.getTablePrefix();
		String tableName = tablePrimaryModel.getTableName();
		String modelName = null;
		if(EmptyUtils.isNotEmpty(tablePrefix) && tableName.toUpperCase().startsWith(tablePrefix.toUpperCase())){
			modelName = StringUtil.underlineToCamelhump(tableName.substring(tablePrefix.length()),false);
		}else{
			modelName = StringUtil.underlineToCamelhump(tableName,false);
		}
		
		context.put("tableName", tableName);
		context.put("tableModelName", modelName);
		context.put("modelName", modelName+"Model");
		context.put("mapperName", modelName+"Mapper");
		context.put("package", modelPackage);
		context.put("modelClassName", modelPackage + "." + context.get("modelName"));
		context.put("mapperClassName", modelPackage + "." + context.get("mapperName"));
		return context;
	}
	
	/**
	 * 获取配置文件域参数
	 * @param dataSourcePool
	 * @param tablePrimaryModel
	 * @param basicPath 项目绝对路径(精确到: 项目/src/main/java/)
	 * @param modelPackage model生成的包路径
	 * @return
	 */
	public static VelocityContext getConfigContext(DruidDataSource dataSourcePool,
			TablePrimaryModel tablePrimaryModel,
			String basicPath,
			String modelPackage){
		VelocityContext commonContext = GeneratorUtils.getCommonContext(tablePrimaryModel,modelPackage);
		VelocityContext context = new VelocityContext();
		context.put("jdbcDriver", dataSourcePool.getDriverClassName());
		context.put("jdbcUrl", dataSourcePool.getUrl());
		context.put("jdbcName", dataSourcePool.getUsername());
		context.put("jdbcPassword", dataSourcePool.getPassword());
		context.put("primaryColumnName", tablePrimaryModel.getPrimaryColumnName());
		context.put("autoIncrement", tablePrimaryModel.isAutoIncrement());
		context.put("basicPath", basicPath.replaceAll("\\\\", "/"));

		return GeneratorUtils.mergeVelocityContext(context, commonContext);
	}
	
	/**
	 * 合并VelocityContext
	 * @param context1
	 * @param context2
	 * @return
	 */
	private static VelocityContext mergeVelocityContext(VelocityContext context1,VelocityContext context2){
		VelocityContext context = new VelocityContext();
		Object[] keys = context1.getKeys();
		for(Object key : keys){
			String keyStr = key.toString();
			context.put(keyStr, context1.get(keyStr));
		}
		
		keys = context2.getKeys();
		for(Object key : keys){
			String keyStr = key.toString();
			context.put(keyStr, context2.get(keyStr));
		}
		return context;
	}
	
	
	
	
	
	/**
	 * 创建此目录
	 * @param dir
	 * @return
	 */
	public static String createDirs(String dir){
		File dirFile = new File(dir);
		if(!dirFile.exists()){
			dirFile.mkdirs();
		}
		return dir;
	}
	
	/**
	 * 给path后面添加斜线
	 * @param path
	 * @return
	 */
	public static String addPathLine(String path){
		if(!path.endsWith("/")){
			path += "/";
		}
		return path;
	}
	
	/**
	 * 获取一个新的包名（用于创建新的扩展model）
	 * @param packageName
	 * @return
	 */
	public static String getNewPackage(String packageName){
		return packageName.substring(0,packageName.lastIndexOf("."));
	}
	

	/**
	 * @description: 通过class获取类名
	 * @param: [className]
	 * @return: java.lang.String
	 * @author: hcl
	 * @date: created in 2018/1/19 9:36
	 */
	public static String getSimpleClassName(String className){
		return className.substring(className.lastIndexOf(".")+1,className.length());
	}

	/**
	 * @description: 根据TablePrimaryModel 获取Model名称,会去除 前缀
	 * @param: [tablePrimaryModel]
	 * @return: java.lang.String
	 * @author: hcl
	 * @date: created in 2018/1/19 16:18
	 */
	public static String getModelName(TablePrimaryModel tablePrimaryModel){
		String tablePrefix = tablePrimaryModel.getTablePrefix();
		String tableName = tablePrimaryModel.getTableName();
		String modelName = null;
		if(EmptyUtils.isNotEmpty(tablePrefix) && tableName.toUpperCase().startsWith(tablePrefix.toUpperCase())){
			modelName = StringUtil.underlineToCamelhump(tableName.substring(tablePrefix.length()),false);
		}else{
			modelName = StringUtil.underlineToCamelhump(tableName,false);
		}
		return modelName;
	}

}
